/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2016-9-7       Urey         the first version
 */

#ifndef _MIPS_CONTEXT_ASM_H_
#define _MIPS_CONTEXT_ASM_H_

#define CONTEXT_SIZE    ( STK_CTX_SIZE + FPU_ADJ )
#ifdef __mips_hard_float
#define FPU_ADJ         (32 * 4 + 8)        /* FP0-FP31 + CP1_STATUS */
#define FPU_CTX         ( CONTEXT_SIZE - FPU_ADJ )
#else
#define FPU_ADJ         0
#endif



#ifdef __ASSEMBLY__

#ifdef __mips_hard_float
.global _fpctx_save
.global _fpctx_load
#endif

.macro SAVE_CONTEXT
    .set    push
    .set    noat
    .set    noreorder
    .set    volatile

    //save SP
    move    k1,     sp
    move    k0,     sp
    subu    sp,     k1,     CONTEXT_SIZE
    sw      k0,     (29 * 4)(sp)

    //save REG
    sw      $0,     ( 0 * 4)(sp)
    sw      $1,     ( 1 * 4)(sp)
    sw      $2,     ( 2 * 4)(sp)
    sw      $3,     ( 3 * 4)(sp)
    sw      $4,     ( 4 * 4)(sp)
    sw      $5,     ( 5 * 4)(sp)
    sw      $6,     ( 6 * 4)(sp)
    sw      $7,     ( 7 * 4)(sp)
    sw      $8,     ( 8 * 4)(sp)
    sw      $9,     ( 9 * 4)(sp)
    sw      $10,    (10 * 4)(sp)
    sw      $11,    (11 * 4)(sp)
    sw      $12,    (12 * 4)(sp)
    sw      $13,    (13 * 4)(sp)
    sw      $14,    (14 * 4)(sp)
    sw      $15,    (15 * 4)(sp)
    sw      $16,    (16 * 4)(sp)
    sw      $17,    (17 * 4)(sp)
    sw      $18,    (18 * 4)(sp)
    sw      $19,    (19 * 4)(sp)
    sw      $20,    (20 * 4)(sp)
    sw      $21,    (21 * 4)(sp)
    sw      $22,    (22 * 4)(sp)
    sw      $23,    (23 * 4)(sp)
    sw      $24,    (24 * 4)(sp)
    sw      $25,    (25 * 4)(sp)
    /* K0 K1 */
    sw      $28,    (28 * 4)(sp)
    /* SP */
    sw      $30,    (30 * 4)(sp)
    sw      $31,    (31 * 4)(sp)

    /* STATUS CAUSE EPC.... */
    mfc0    $2,     CP0_STATUS
    sw      $2,     STK_OFFSET_SR(sp)

    mfc0    $2,     CP0_CAUSE
    sw      $2,     STK_OFFSET_CAUSE(sp)

    mfc0    $2,     CP0_BADVADDR
    sw      $2,     STK_OFFSET_BADVADDR(sp)

    MFC0    $2,     CP0_EPC
    sw      $2,     STK_OFFSET_EPC(sp)

    mfhi    $2
    sw      $2,     STK_OFFSET_HI(sp)

    mflo    $2
    sw      $2,     STK_OFFSET_LO(sp)
#ifdef __mips_hard_float
    add     a0,     sp,STK_CTX_SIZE

    mfc0    t0,     CP0_STATUS
    .set    push
    .set    at
    or      t0,     M_StatusCU1
    .set    push
    mtc0    t0,     CP0_STATUS

    cfc1    t0,     CP1_STATUS
    sw      t0   ,  0x00(a0)
    swc1    $f0,(0x04 *  1)(a0)
    swc1    $f1,(0x04 *  2)(a0)
    swc1    $f2,(0x04 *  3)(a0)
    swc1    $f3,(0x04 *  4)(a0)
    swc1    $f4,(0x04 *  5)(a0)
    swc1    $f5,(0x04 *  6)(a0)
    swc1    $f6,(0x04 *  7)(a0)
    swc1    $f7,(0x04 *  8)(a0)
    swc1    $f8,(0x04 *  9)(a0)
    swc1    $f9,(0x04 * 10)(a0)
    swc1   $f10,(0x04 * 11)(a0)
    swc1   $f11,(0x04 * 12)(a0)
    swc1   $f12,(0x04 * 13)(a0)
    swc1   $f13,(0x04 * 14)(a0)
    swc1   $f14,(0x04 * 15)(a0)
    swc1   $f15,(0x04 * 16)(a0)
    swc1   $f16,(0x04 * 17)(a0)
    swc1   $f17,(0x04 * 18)(a0)
    swc1   $f18,(0x04 * 19)(a0)
    swc1   $f19,(0x04 * 20)(a0)
    swc1   $f20,(0x04 * 21)(a0)
    swc1   $f21,(0x04 * 22)(a0)
    swc1   $f22,(0x04 * 23)(a0)
    swc1   $f23,(0x04 * 24)(a0)
    swc1   $f24,(0x04 * 25)(a0)
    swc1   $f25,(0x04 * 26)(a0)
    swc1   $f26,(0x04 * 27)(a0)
    swc1   $f27,(0x04 * 28)(a0)
    swc1   $f28,(0x04 * 29)(a0)
    swc1   $f29,(0x04 * 30)(a0)
    swc1   $f30,(0x04 * 31)(a0)
    swc1   $f31,(0x04 * 32)(a0)

    nop
#endif

    //restore a0
    lw      a0,     (REG_A0 * 4)(sp)

    .set    pop
.endm


.macro RESTORE_CONTEXT
    .set    push
    .set    noat
    .set    noreorder
    .set    volatile

#ifdef __mips_hard_float
    add     a0, sp,STK_CTX_SIZE

    mfc0    t0, CP0_STATUS
    .set    push
    .set    at
    or      t0, M_StatusCU1
    .set    noat
    mtc0    t0, CP0_STATUS

    lw      t0   ,   0x00(a0)
    lwc1    $f0,(0x04 *  1)(a0)
    lwc1    $f1,(0x04 *  2)(a0)
    lwc1    $f2,(0x04 *  3)(a0)
    lwc1    $f3,(0x04 *  4)(a0)
    lwc1    $f4,(0x04 *  5)(a0)
    lwc1    $f5,(0x04 *  6)(a0)
    lwc1    $f6,(0x04 *  7)(a0)
    lwc1    $f7,(0x04 *  8)(a0)
    lwc1    $f8,(0x04 *  9)(a0)
    lwc1    $f9,(0x04 * 10)(a0)
    lwc1   $f10,(0x04 * 11)(a0)
    lwc1   $f11,(0x04 * 12)(a0)
    lwc1   $f12,(0x04 * 13)(a0)
    lwc1   $f13,(0x04 * 14)(a0)
    lwc1   $f14,(0x04 * 15)(a0)
    lwc1   $f15,(0x04 * 16)(a0)
    lwc1   $f16,(0x04 * 17)(a0)
    lwc1   $f17,(0x04 * 18)(a0)
    lwc1   $f18,(0x04 * 19)(a0)
    lwc1   $f19,(0x04 * 20)(a0)
    lwc1   $f20,(0x04 * 21)(a0)
    lwc1   $f21,(0x04 * 22)(a0)
    lwc1   $f22,(0x04 * 23)(a0)
    lwc1   $f23,(0x04 * 24)(a0)
    lwc1   $f24,(0x04 * 25)(a0)
    lwc1   $f25,(0x04 * 26)(a0)
    lwc1   $f26,(0x04 * 27)(a0)
    lwc1   $f27,(0x04 * 28)(a0)
    lwc1   $f28,(0x04 * 29)(a0)
    lwc1   $f29,(0x04 * 30)(a0)
    lwc1   $f30,(0x04 * 31)(a0)
    lwc1   $f31,(0x04 * 32)(a0)
    ctc1    t0,     CP1_STATUS                                            ;/*  restore fpp status reg      */

    nop
#endif

    /* ͨ通用寄存器 */
    /* ZERO */
    lw      $1,     ( 1 * 4)(sp)
    /* V0   */
    lw      $3,     ( 3 * 4)(sp)
    lw      $4,     ( 4 * 4)(sp)
    lw      $5,     ( 5 * 4)(sp)
    lw      $6,     ( 6 * 4)(sp)
    lw      $7,     ( 7 * 4)(sp)
    lw      $8,     ( 8 * 4)(sp)
    lw      $9,     ( 9 * 4)(sp)
    lw      $10,    (10 * 4)(sp)
    lw      $11,    (11 * 4)(sp)
    lw      $12,    (12 * 4)(sp)
    lw      $13,    (13 * 4)(sp)
    lw      $14,    (14 * 4)(sp)
    lw      $15,    (15 * 4)(sp)
    lw      $16,    (16 * 4)(sp)
    lw      $17,    (17 * 4)(sp)
    lw      $18,    (18 * 4)(sp)
    lw      $19,    (19 * 4)(sp)
    lw      $20,    (20 * 4)(sp)
    lw      $21,    (21 * 4)(sp)
    lw      $22,    (22 * 4)(sp)
    lw      $23,    (23 * 4)(sp)
    lw      $24,    (24 * 4)(sp)
    lw      $25,    (25 * 4)(sp)
    lw      $26,    (26 * 4)(sp)
    lw      $27,    (27 * 4)(sp)
    lw      $28,    (28 * 4)(sp)
    /* SP */
    lw      $30,    (30 * 4)(sp)
    lw      $31,    (31 * 4)(sp)


    /* STATUS CAUSE EPC.... */
    lw      $2,    STK_OFFSET_HI(sp)
    mthi    $2
    lw      $2,     STK_OFFSET_LO(sp)
    mtlo    $2

    lw      $2,     STK_OFFSET_SR(sp)
    mtc0    $2,     CP0_STATUS

    lw      $2,     STK_OFFSET_BADVADDR(sp)
    mtc0    $2,     CP0_BADVADDR

    lw      $2,     STK_OFFSET_CAUSE(sp)
    mtc0    $2,     CP0_CAUSE

    lw      $2,     STK_OFFSET_EPC(sp)
    MTC0    $2,     CP0_EPC

    //restore $2
    lw      $2,     ( 2 * 4)(sp)
    //restore sp
    lw      $29,    (29 * 4)(sp)

    eret
    nop
    .set    pop
.endm
#endif
#endif /* _MIPS_CONTEXT_ASM_H_ */
